#pragma once

#include "../umlmodel_global.h"

#include <memory>
#include <vector>

#include "ConnectorKind.h"
#include "Feature.h"

using std::make_shared;
using std::shared_ptr;
using std::vector;

namespace uml {
class Association;
class Behavior;
class ConnectorEnd;

/// <summary>
/// Connector
/// A Connector specifies links that enables communication between two or more
/// instances. In contrast to Associations, which specify links between any instance
/// of the associated Classifiers, Connectors specify links between instances
/// playing the connected parts only.
/// </summary>
class UMLMODEL_EXPORT Connector : public Feature {

public: // Constructors and destructors
    explicit Connector(const QString& umlType="uml::Connector");

public: // JsonSerializable override
    void fromJson(const QJsonObject& json, QStringList& errorList) override;
    void toJson(QJsonObject& json) override;

public: // Methods
public: // Properties
    /// <summary>
    /// contracts getter
    /// The set of Behaviors that specify the valid interaction patterns across the
    /// Connector.
    /// </summary>
    vector<shared_ptr<Behavior>>& contracts();

    /// <summary>
    /// ends getter
    /// A Connector has at least two ConnectorEnds, each representing the participation
    /// of instances of the Classifiers typing the ConnectableElements attached to the
    /// end. The set of ConnectorEnds is ordered.
    /// </summary>
    vector<shared_ptr<ConnectorEnd>>& ends();

    /// <summary>
    /// kind getter
    /// Indicates the kind of Connector. This is derived: a Connector with one or more
    /// ends connected to a Port which is not on a Part and which is not a behavior port
    /// is a delegation; otherwise it is an assembly.
    /// </summary>
    ConnectorKind kind() const;

    /// <summary>
    /// kind setter
    /// Indicates the kind of Connector. This is derived: a Connector with one or more
    /// ends connected to a Port which is not on a Part and which is not a behavior port
    /// is a delegation; otherwise it is an assembly.
    /// </summary>
    void setKind(ConnectorKind value);

    /// <summary>
    /// redefinedConnectors getter
    /// A Connector may be redefined when its containing Classifier is specialized. The
    /// redefining Connector may have a type that specializes the type of the redefined
    /// Connector. The types of the ConnectorEnds of the redefining Connector may
    /// specialize the types of the ConnectorEnds of the redefined Connector. The
    /// properties of the ConnectorEnds of the redefining Connector may be replaced.
    /// </summary>
    vector<shared_ptr<Connector>>& redefinedConnectors();

    /// <summary>
    /// type getter
    /// An optional Association that classifies links corresponding to this Connector.
    /// </summary>
    shared_ptr<Association> type() const;

    /// <summary>
    /// type setter
    /// An optional Association that classifies links corresponding to this Connector.
    /// </summary>
    void setType(shared_ptr<Association> value);

private: // Fields
    /// <summary>
    /// contracts
    /// The set of Behaviors that specify the valid interaction patterns across the
    /// Connector.
    /// </summary>
    vector<shared_ptr<Behavior>> contracts_;

    /// <summary>
    /// ends
    /// A Connector has at least two ConnectorEnds, each representing the participation
    /// of instances of the Classifiers typing the ConnectableElements attached to the
    /// end. The set of ConnectorEnds is ordered.
    /// </summary>
    vector<shared_ptr<ConnectorEnd>> ends_;

    /// <summary>
    /// kind
    /// Indicates the kind of Connector. This is derived: a Connector with one or more
    /// ends connected to a Port which is not on a Part and which is not a behavior port
    /// is a delegation; otherwise it is an assembly.
    /// </summary>
    ConnectorKind kind_ = ConnectorKind::kassembly;

    /// <summary>
    /// redefinedConnectors
    /// A Connector may be redefined when its containing Classifier is specialized. The
    /// redefining Connector may have a type that specializes the type of the redefined
    /// Connector. The types of the ConnectorEnds of the redefining Connector may
    /// specialize the types of the ConnectorEnds of the redefined Connector. The
    /// properties of the ConnectorEnds of the redefining Connector may be replaced.
    /// </summary>
    vector<shared_ptr<Connector>> redefinedConnectors_;

    /// <summary>
    /// type
    /// An optional Association that classifies links corresponding to this Connector.
    /// </summary>
    shared_ptr<Association> type_;

};

} // namespace uml
